/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#ifndef INCLUDE_SHADER_MESH
#define INCLUDE_SHADER_MESH


#include "shader_line.h"



#ifdef __cplusplus

#include <basic_vec.h>
#include <matXX.h>

using uint = unsigned int;
using uint = uint32;

#define in
#define out
#define inout


#else

//#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
//#extension GL_EXT_shader_16bit_storage : require

#define Inline

#endif


struct S_Vert_MeshDrawProp_PBR {
	uint Offset_MeshProp;
	uint Offset_Matrix;
	uint Offset_ColorProp;
	uint Offset_Element;

	uint DrawType;


	uint Offset_Bones;
	uint Offset_BoneWeiget;
	uint Offset_BonePose;
	uint BoneNum;


	uint Offset_MeshAttr;
	uint Offset_MaterialAtt;
	uint Offset_ObMesh;

	uint Offset_Material;
};

struct S_Vert_MeshDrawProp {
	uint MeshPropOffset;
	uint MatrixOffset;
	uint ColorPropOffset;
	uint DrawType;


	uint VertexOffset;
	uint ElementOffset;


	uint BonesOffset;
	uint BoneNum;
	uint BoneWeigetOffset;
	uint BonePoseOffset;

	uint Offset_MeshAttr;
	uint Offset_MaterialAtt;
	uint ObMesh_Offset;

	uint Offset_Face_AdjacencyID;
	uint Offset_Face_Normal;
	uint Offset_Face_Center;
	uint Offset_Face;

};



struct S_Geom_MeshDrawProp {
	uint Offset_Face_AdjacencyID;
	uint Offset_Face_Normal;
	uint Offset_Face_Center;
	uint Offset_Face;

	uint Offset_MeshAttr;
	uint Offset_MaterialAttr;
};



struct S_ShaderConst_TextAttr {

	uint64_t m_Address_TextCoord;
	uint64_t m_Address_TextID;
	uint64_t m_Address_TextID_Range;
	
	uint64_t m_Address_MeshPropOffset;

	//uint64_t fontSize;
	vec2	m_CoordOffset;
	float	fontSize;

	uint MatrixOffset;
	uint ColorPropOffset;
	//uint BonesOffset;

	uint m_L_BackgroundText;
	uint m_R_BackgroundText;
	//uint64_t m_Address_TextBuond;
};




struct S_RayIntersectionMemProp {
	uint64_t m_Address_Origin;
	uint64_t m_Address_Direction;
	uint64_t m_Address_RayLength;

	uint64_t m_Address_RtOb;
	uint64_t m_Address_IntersectionPoint;
	uint64_t m_Address_IntersectionNormal;
	uint64_t m_Address_IntersectionDis;


	uint mem_OriginNum;
	uint mem_DirectionNum;
	uint mem_RayLengthNum;
	uint mem_IntersectionPointNum;
	uint mem_IntersectionDisNum;
	
	uint mem_Flage;

};


struct S_MeshPick {
	uint VertOffset;
	uint IndexOffset;
};


struct S_Pick {
	mat4 matrix;
	mat4 camera_matrix;
	vec4 s;
	vec4 dir;
	uint vertOffset;
	uint indexOffset;
};


struct S_VertBone {
	uint bone_offset;
	uint num;
};

struct S_BoneMap {
	//uint num;
	uint boneID;
	float weigth;
};

struct S_BonePose {
	vec4 quat;
	//变换前尾骨节坐标和骨骼长度
	vec4 tranformBoneA;
	//变换后尾骨节坐标
	vec4 tranformBoneB;

	//vec3 SPos;
	vec3 dir;
	int select;
	int ID;

};







#ifdef __cplusplus

Inline uint f_glsl_Build_ShaderType(uint faceType, uint tranformType) {
	return faceType | tranformType << 8;
}


Inline void f_lineMeshTranform(vec3& point, const vec3& normal, const S_MeshTranformProp& prop, const Mat44f& ModelMat, const mat3& viewInverseMat, vec3 camPos) {
	//vec3 coord;
	switch (prop.m_TransformMode & 0x0000ffff) {

		case DEF_MESH_LINE_TRANFORMTYPEMODEL_NBILLBOARD: {
			point *= viewInverseMat;
			point += vec3{ ModelMat.m30, ModelMat.m31, ModelMat.m32 };
			return;
		}
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_GAZE: {
			vec3 H = viewInverseMat * vec3{1, 0, 0};
			vec3 V = viewInverseMat * vec3{0, 0, 1};

			vec3 dirLine = normalize(f_mat44_to_33(ModelMat) * vec3{0, 1, 0});
			vec3 right = normalize(f_mat44_to_33(ModelMat) * vec3{1, 0, 0});
			H = normalize(cross(dirLine, V));

			point = H * point.x + V * point.z + dirLine * point.y;
			//point += vec3{ModelMat.m30, ModelMat.m31, ModelMat.m32};
			break;
		}

		case DEF_MESH_LINE_TRANFORMTYPEMODEL_CenterZoom: {
			point.x = point.x * prop.m_XScale;
			point.y = point.y * prop.m_YScale;
			point.z = point.z * prop.m_ZScale;
			break;
		}
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_NormalToWeigth: {
			point *= vec3{prop.m_XScale, prop.m_YScale, prop.m_ZScale};
			break;
		}

		case DEF_MESH_LINE_TRANFORMTYPEMODEL_CAMERAGAZE: {
			point = viewInverseMat * point;
			break;
		}
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_PointLink: {
			point.x = point.x * prop.m_XScale;
			point.y = point.y * prop.m_YScale;
			point.z = point.z * prop.m_ZScale;

			point += vec3{ModelMat.m30, ModelMat.m31, ModelMat.m32};
			break;
		}
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_Cylinder: {
			point *= prop.m_Scale;
			
			point.x += prop.m_XScale * normal.x;
			point.y += prop.m_YScale * normal.y;
			point.z += prop.m_ZScale * normal.z;

			point = ModelMat * point;
			return;
		}
		case DEF_MESH_TRANFORMTYPE_Mark: {
			point *= viewInverseMat;
			break;
		}
	}

	

	switch (prop.m_TransformMode >> 16) {
		case DEF_MESH_Tranform_NONE: {
			point += vec3{ prop.m_XMove, prop.m_YMove, prop.m_ZMove };
			point *= prop.m_Scale;
			point = ModelMat * point;
			break;
		}
		case DEF_MESH_Tranform_Independent: {
			point = f_mat44_3x3(ModelMat) * point + _Vec3(ModelMat.m30, ModelMat.m31, ModelMat.m32);
			break;
		}
		case DEF_MESH_Tranform_ViewSize: {
			point *= length(_Vec3(ModelMat.m30, ModelMat.m31, ModelMat.m32) - camPos) * prop.m_Scale;
			point += _Vec3(ModelMat.m30, ModelMat.m31, ModelMat.m32);
			break;
		}
	}
}

#else

bool f_lineMeshTranform(inout vec4 point, in vec3 normal, in S_MeshTranformProp prop, in mat4 ModelMat, in mat3 viewInverseMat, in vec3 camPos) {
	
	switch (prop.m_TransformMode & 0x0000ffff) {
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_NBILLBOARD: {
			point.xyz *= viewInverseMat;
			point.xyz += ModelMat[3].xyz;
			
			return true;
		}
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_VERTICAL: {
			point.xyz = vec3(0, -length(ModelMat * point), 0);
			break;
		}
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_GAZE: {
			mat3 rot = viewInverseMat;
			vec3 H = (vec3(1, 0, 0) * rot);
			vec3 V = (vec3(0, 0, 1) * rot);
			vec3 dirLine = normalize(mat3(ModelMat) * vec3(0, 1, 0));
			vec3 right = normalize(mat3(ModelMat) * vec3(1, 0, 0));
			H = normalize(cross(dirLine, V));
		
			point.xyz = H * point.x + V * point.z + dirLine * point.y;
			//point.xyz += ModelMat[3].xyz;
			break;
			//return true;
		}
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_CenterZoom: {
			point.xyz *= vec3(prop.m_XScale, prop.m_YScale, prop.m_ZScale);
			break;
		}
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_NormalToWeigth: {
			point.xyz *= vec3(prop.m_XScale, prop.m_YScale, prop.m_ZScale) * normal;
			break;
		}
		
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_CAMERAGAZE: {
			point.xyz = viewInverseMat * point.xyz;
			break;
		}
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_PointLink: {
			//coord.xyz = prop.m_XScale * point.xyz;
			point.xyz = point.xyz * vec3(prop.m_XScale, prop.m_YScale, prop.m_ZScale);
			point.xyz += ModelMat[3].xyz;
			return true;
		}
		case DEF_MESH_LINE_TRANFORMTYPEMODEL_Cylinder: {
			point.xyz *= prop.m_Scale;
			point.xyz += vec3(prop.m_XScale, prop.m_YScale, prop.m_ZScale) * normal;
			break;
		}
		case DEF_MESH_TRANFORMTYPE_Mark: {
			point.xyz *= viewInverseMat;
			break;
		}
		default: {
			break;
		}
	}

	
	
	
	switch (prop.m_TransformMode >> 16) {
		case DEF_MESH_Tranform_NONE: {
			point.xyz += vec3(prop.m_XMove, prop.m_YMove, prop.m_ZMove);
			point.xyz *= prop.m_Scale;

			point = ModelMat * point;
			break;
		}
		case DEF_MESH_Tranform_Independent: {
			mat3 rot = mat3(ModelMat);
			rot[0] = normalize(rot[0]);
			rot[1] = normalize(rot[1]);
			rot[2] = normalize(rot[2]);
			point = vec4(rot * point.xyz + ModelMat[3].xyz, 1);
			return true;
		}
		case DEF_MESH_Tranform_ViewSize: {
			point.xyz *= length(ModelMat[3].xyz - camPos) * prop.m_Scale;
			point = vec4(point.xyz + ModelMat[3].xyz, 1);
			return true;
		}
	}
	return false;
}





#endif




#undef in
#undef out





#endif




